#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <string.h>
#include <errno.h>
#include <netinet/in.h>
#include <fcntl.h>

#define ERROR(errmsg) do{\
                            perror(errmsg);\
                            exit(-1);\
                        }while(0);
#define N 128

void download(int socket,struct sockaddr_in addr)
{
    //输入下载文件
    char filename[N] = "";
    printf("请输入需下载文件>");
    scanf("%s",filename);

    char text[1024] = "";
    int textlen = 0;
    int fd;
    int flags = 0;
    int num = 0;    //记录确认号
    ssize_t bytes = 0;    

    //发送客户端下载请求（01text.txt\0octet\0）
    textlen = sprintf(text,"%c%c%s%c%s%c",0,1,filename,0,"octet",0);
    socklen_t seraddr_len = sizeof(addr);
    if(sendto(socket,text,textlen,0,(struct sockaddr*)&addr,seraddr_len) == -1)
    {
        ERROR("fail to sendto");
    }

    while(1)
    {
        //接收服务端数据
        if((bytes = recvfrom(socket,text,sizeof(text),0,(struct sockaddr*)&addr,&seraddr_len)) == -1)
        {
            ERROR("fail to recvfrom");
        }
        
        //判断操作码执行相应处理
        if(text[1] == 5)    //错误
        {
            //打印错误信息
            printf("%s\n",text+4);
            exit(-1);
        }

        else if(text[1] == 3)   //数据包
        {
            if(flags == 0)
            {
                //创建文件
                if((fd = open(filename,O_WRONLY|O_CREAT|O_TRUNC,0664)) < 0)
                {
                    ERROR("fail to open");
                }
                flags = 1;
            }
            //写入数据并向服务端发送确认码
            if(num+1 == ntohs(*(unsigned short*)(text+2))&& bytes == 516)
            {
                num = ntohs(*(unsigned short*)(text+2));
                //写入数据
                write(fd,text+4,bytes-4);

                //发送确认码
                text[1] = 4;
                if(sendto(socket,text,4,0,(struct sockaddr*)&addr,seraddr_len) == -1)
                {
                    ERROR("fail to sendto");
                }
            }
            //最后一次数据传送，文件下载完毕
            else
            {
                num = ntohs(*(unsigned short*)(text+2));
                //写入数据
                write(fd,text+4,bytes-4);
                write(fd,"\n",1);

                //发送确认码
                text[1] = 4;
                if(sendto(socket,text,4,0,(struct sockaddr*)&addr,seraddr_len) == -1)
                {
                    ERROR("fail to sendto");
                }
                printf("文件下载完成!\n");
                break;
            }
        }
    }
    //关闭文件描述符
    close(fd);
    return;
}



int main(int argc,char const *argv[])
{
    //创建套接字
    int sock;
    if((sock = socket(AF_INET,SOCK_DGRAM,0)) == -1)
    {
        ERROR("fail to socket");
    }

    //初始化服务端地址结构体
    struct sockaddr_in server_tftp;
    server_tftp.sin_family = AF_INET;
    server_tftp.sin_addr.s_addr = inet_addr(argv[1]);
    server_tftp.sin_port = htons(69);

    //下载文件
    download(sock,server_tftp);

    //关闭套接字
    close(sock);
    return 0;
}